var chart_nl;
var dragok = false;
var canvas_nl;

var preMouseX =0;
var preMouseY =0;

var offsetX = 40; // initial border of chart
var offsetY = 40;
var widthFloat = 0;
var heightFloat = 0;

function drawNetworkLayout() {
	
	chart_nl.draw();
	
	canvas_nl = document.getElementById("canvas_nl");
	canvas_nl.addEventListener("mousedown", nl_mouseDown, false);
	canvas_nl.addEventListener("mouseup", nl_mouseUp, false);
	canvas_nl.addEventListener("mouseout", nl_mouseUp, false);
	
	canvas_nl.addEventListener('DOMMouseScroll', n_wheel, false);
	canvas_nl.addEventListener("mousewheel", n_wheel, false);
}

function nl_mouseDown(e) {
	var xcanvas = $(this).offset().left;
	var ycanvas = $(this).offset().top;
	if (e.pageX > xcanvas + offsetX + widthFloat / 2 && e.pageX < xcanvas + this.width - offsetX - widthFloat / 2
			&& e.pageY > ycanvas + offsetY + heightFloat / 2
			&& e.pageY < ycanvas + this.height - offsetY - heightFloat / 2) {
		dragok = true;
		preMouseX = e.pageX;
		preMouseY = e.pageY;
		canvas_nl.onmousemove = mouseMove;
	};
}

function nl_mouseUp(e){
	 dragok = false;
	 canvas_nl.onmousemove = null;
}

function mouseMove(e){
	 if(dragok) {
		 chart_nl.setMove(e.pageX - preMouseX, e.pageY - preMouseY);
		 preMouseX= e.pageX;
		 preMouseY = e.pageY;
	 }
}

function n_wheel(event) {
	var delta = 0;
	if (!event) /* For IE. */
		event = window.event;
	if (event.wheelDelta) { /* IE/Opera. */
		delta = event.wheelDelta / 120;
	} else if (event.detail) { //Mozilla
		delta = -event.detail / 3;
	}
	if (delta)
		wheelHandle(delta);
	/** Prevent default actions caused by mouse wheel.
	 * That might be ugly, but we handle scrolls somehow
	 * anyway, so don't bother here..
	 */
	if (event.preventDefault)
		event.preventDefault();
	event.returnValue = false;
}

function wheelHandle(y) {
	chart_nl.scale(Math.pow(0.8, y));
}

function clearNetworkLayout() {
	chart_nl.clean();
}

function Network_Layout_chart(canvasId) {
	var id = canvasId;
	var canvasData = null;

	var context = null;

	var canvas = document.getElementById(id);
	var width = $(canvas).attr("width");
	var height = $(canvas).attr("Height");

	var x_scaleNum = 40;
	var y_scaleNum = 25;

	var x0_val = -10;
	var xm_val = 10;
	var y0_val = -5;
	var ym_val = 5;

	var x0 = 0;
	var xm = 0;
	var y0 = 0;
	var ym = 0;

	this.draw = function() {

		this.inialNum();

		this.createBackgroud();
		this.createCoordniate();
		this.drawDots();
	};
	
	this.clean = function() {
		if (context != null) {
			context.clearRect(0, 0, width, height);
			
			//weird clearRect only doesn't work
			context.beginPath();
			context.closePath();
		}
	};
	
		this.scale = function(s) {
		x0_val = Math.round(x0_val * s * 10000) / 10000;
		xm_val = Math.round(xm_val * s * 10000) / 10000;
		y0_val = Math.round(y0_val * s * 10000) / 10000;
		ym_val = Math.round(ym_val * s * 10000) / 10000;
		var x_d = xm_val - x0_val;
		var y_d = ym_val - y0_val;
		if(x_d >10000 || x_d <0.001 || y_d > 10000 || y_d <0.001){
			return;
		}
		this.clean();
		this.draw();
	};
	
	this.setMove = function(mouseX,mouseY){
		x0_val = x0_val - mouseX*(xm_val - x0_val)/(xm - x0);
		xm_val = xm_val - mouseX*(xm_val - x0_val)/(xm - x0);
		y0_val = y0_val - mouseY*(ym_val - y0_val)/(ym - y0);
		ym_val = ym_val - mouseY*(ym_val - y0_val)/(ym - y0);
		
		this.clean();
		this.draw();
	};

	this.inialNum = function() {
		context = document.getElementById(id).getContext("2d");

		widthFloat = (width - 2 * offsetX) % x_scaleNum;
		heightFloat = (height - 2 * offsetY) % y_scaleNum;
		x0 = offsetX + widthFloat / 2;
		xm = width - widthFloat / 2 - offsetX;
		y0 = height - heightFloat / 2 - offsetY;
		ym = offsetY + heightFloat / 2;
	};

	this.createBackgroud = function() {

		context.strokeStyle = "#000";
		context.lineWidth = 1;
		context.lineCap = "round"; // round, square, butt

		var gradient = context.createLinearGradient(x0 + 20, y0, x0, ym);
		gradient.addColorStop(0, "#eee");
		gradient.addColorStop(1, "#fff");
		context.fillStyle = gradient;

		context.fillRect(x0, ym, xm - x0, y0 - ym);
	};

	this.createCoordniate = function() {

		context.strokeStyle = "#000";
		context.lineWidth = 1;
		context.lineCap = "round"; // round, square, butt

		// word
		context.fillStyle = "#000";
		context.textAlign = "center";
		context.font = "bold 12pt Calibri";
		context.fillText("Network Layout of 2D Guassian Function", width / 2, offsetY - 10);
		context.font = "11pt Calibri";
		context.fillText("X-Coordinator", width / 2, y0 + offsetY);

		context.save();
		context.translate(x0, y0);
		context.rotate(-Math.PI / 2);
		context.textBaseline = "middle";
		context.textAlign = "center";
		context.fillText("Y-Coordinator", height / 2 - offsetX, -offsetX + 4);
		context.restore();
		
		// border line
		context.moveTo(x0, y0);
		context.lineTo(x0, ym);
		context.moveTo(x0, y0);
		context.lineTo(xm, y0);
		context.moveTo(x0, ym);
		context.lineTo(xm, ym);
		context.moveTo(xm, y0);
		context.lineTo(xm, ym);

		context.textBaseline = "middle";
	
		var stepY = (ym_val - y0_val) * 5 / y_scaleNum;
		if (stepY >= 1 && stepY < 10) { 
			stepY = Math.round(stepY);
		}else if(stepY >= 0.1 && stepY < 1){
			stepY = Math.round(stepY*10)/10;
		}else if(stepY >= 10 && stepY < 100){
			stepY = Math.round(stepY/10)*10;
		}else if(stepY >= 0.01 && stepY < 0.1){
			stepY = Math.round(stepY*100)/100;
		}else if(stepY >= 100 && stepY < 1000){
			stepY = Math.round(stepY/100)*100;
		}else if(stepY >= 0.001 && stepY < 0.01){
			stepY = Math.round(stepY*1000)/1000;
		}else if(stepY >= 1000 && stepY < 10000){
			stepY = Math.round(stepY/1000)*1000;
		}else if(stepY >= 0.0001 && stepY < 0.001){
			stepY = Math.round(stepY*10000)/10000;
		}

		// y  scale number
		for ( var i = Math.ceil(y0_val/stepY)*stepY; i <= ym_val; i = i + stepY) {
			context.fillText(Math.round(i*10000)/10000,  x0 - 16, y0 + (i-y0_val) * (ym-y0)/(ym_val - y0_val));
			
			context.moveTo(x0 - 5, y0 + (i-y0_val) * (ym-y0)/(ym_val - y0_val));
			context.lineTo(x0 + 5, y0 + (i-y0_val) * (ym-y0)/(ym_val - y0_val));
		}
		
		// y coordinator
		for ( var i =  Math.ceil(y0_val/stepY)*stepY; i < ym_val; i = i + stepY / 5) {
			context.moveTo(x0 - 2, y0 + (i - y0_val) * (ym - y0) / (ym_val - y0_val));
			context.lineTo(x0 + 2, y0 + (i - y0_val) * (ym - y0) / (ym_val - y0_val));
		}
		
		for ( var i =  Math.ceil(y0_val/stepY)*stepY; i > y0_val; i = i - stepY / 5) {
			context.moveTo(x0 - 2, y0 + (i - y0_val) * (ym - y0) / (ym_val - y0_val));
			context.lineTo(x0 + 2, y0 + (i - y0_val) * (ym - y0) / (ym_val - y0_val));
		}

		// x scale number
		var stepX = (xm_val - x0_val) * 5 / x_scaleNum;
		if (stepX >= 1 && stepX < 10) { 
			stepX = Math.round(stepX);
		}else if(stepX >= 0.1 && stepX < 1){
			stepX = Math.round(stepX*10)/10;
		}else if(stepX >= 10 && stepX < 100){
			stepX = Math.round(stepX/10)*10;
		}else if(stepX >= 0.01 && stepX < 0.1){
			stepX = Math.round(stepX*100)/100;
		}else if(stepX >= 100 && stepX < 1000){
			stepX = Math.round(stepX/100)*100;
		}else if(stepX >= 0.001 && stepX < 0.01){
			stepX = Math.round(stepX*1000)/1000;
		}else if(stepX >= 1000 && stepX < 10000){
			stepX = Math.round(stepX/1000)*1000;
		}else if(stepX >= 0.001 && stepX < 0.01){
			stepX = Math.round(stepX*1000)/1000;
		}

		for ( var i = Math.ceil(x0_val/stepX)*stepX; i <= xm_val; i = i + stepX) {
			context.fillText(Math.round(i*10000)/10000, x0 + (i-x0_val) * (xm-x0)/(xm_val - x0_val), y0 + 18);
			
			context.moveTo(x0 + (i-x0_val) * (xm-x0)/(xm_val - x0_val), y0 - 5);
			context.lineTo(x0 + (i-x0_val) * (xm-x0)/(xm_val - x0_val), y0 + 5);
		}

		// x coordinator
		for ( var i = Math.ceil(x0_val/stepX)*stepX; i < xm_val; i = i + stepX / 5) {
			context.moveTo(x0 + (i-x0_val) * (xm-x0)/(xm_val - x0_val), y0 - 2);
			context.lineTo(x0 + (i-x0_val) * (xm-x0)/(xm_val - x0_val), y0 + 2);
		}
		
		for ( var i = Math.ceil(x0_val/stepX)*stepX; i > x0_val; i = i - stepX / 5) {
			context.moveTo(x0 + (i-x0_val) * (xm-x0)/(xm_val - x0_val), y0 - 2);
			context.lineTo(x0 + (i-x0_val) * (xm-x0)/(xm_val - x0_val), y0 + 2);
		}

		context.stroke();
		
		dotL = 12;
		canvasData = context.getImageData(0, 0, width, height);
		// dotted line
		for ( var i = Math.ceil(x0_val); i <= xm_val; i = i + stepX) {
			for ( var x = y0; x >= ym; x = x - dotL) {
				drawPixel(x0 + (i-x0_val) * (xm-x0)/(xm_val - x0_val), x, 0, 0, 0, 64);
				drawPixel(x0 + (i-x0_val) * (xm-x0)/(xm_val - x0_val), x + 1, 0, 0, 0, 64);
				drawPixel(x0 + (i-x0_val) * (xm-x0)/(xm_val - x0_val), x + 2, 0, 0, 0, 64);
			};
		}
		
		pixelStroke(context, canvasData);
	};

	this.drawDots = function() {
		value_to_x_unit = (width - widthFloat - 2 * offsetX) / (xm_val - x0_val);
		value_to_y_unit = (height - heightFloat - 2 * offsetY) / (ym_val - y0_val);
		context.fillStyle = "#000";

		rows = $('#gene-table').getGridParam('selarrrow');
		for ( var i = 0; i < rows.length; i++) {
			row = $('#gene-table').getRowData(rows[i]);
			if (row["X Position"] >= x0_val && row["X Position"] <= xm_val && row["Y Position"] >= y0_val
					&& row["Y Position"] <= ym_val)
				this.drawDot(row["X Position"], row["Y Position"]);
		}
		;
	};

	this.drawDot = function(x, y) {
		var dx = (x - x0_val) * value_to_x_unit + offsetX + widthFloat / 2;
		var dy = height - (y - y0_val) * value_to_y_unit - offsetY - heightFloat / 2;

		context.beginPath();
		context.arc(dx, dy, 3, 0, Math.PI * 2, true);
		context.closePath();
		context.stroke();
		context.fill();
	};
	
	/**
	 * put a point into canvas data
	 * @param x x coordinate
	 * @param y y coordinate
	 * @param a transparency
	 */
	function drawPixel(x, y, r, g, b, a) {
		x = Math.round(x);

		// 4 - r g b a
		var index = (x + y * width) * 4;

		canvasData.data[index + 0] = r;
		canvasData.data[index + 1] = g;
		canvasData.data[index + 2] = b;
		canvasData.data[index + 3] = a;
	}

	/**
	 * drawing pixel to canvas
	 * 
	 * @param context: canvas context
	 * @param canvasData:must be canvas getImageData(0, 0, canvasWidth, canvasHeight)
	 */
	function pixelStroke(context, canvasData) {
		context.putImageData(canvasData, 0, 0);
	};
};
